package com.appspot.ldsdrawingtool.client;

import com.appspot.ldsdrawingtool.client.command.toolbar.AboutCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.CopyCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.CutCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.DeleteCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.EntityCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.ExportCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.GenerateNaturalLanguageCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.GetHelpOnlineCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.NewCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.OpenCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.PasteCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.RedoCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.RelationshipCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.SaveAsCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.SaveCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.SelectAllCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.ShareCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.ShowSuggestionsCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.ShowSyntaxErrorsCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.UndoCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.ViewAllCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.ZoomInCommand;
import com.appspot.ldsdrawingtool.client.command.toolbar.ZoomOutCommand;
import com.appspot.ldsdrawingtool.client.lds.components.LDSClientModel;
import com.appspot.ldsdrawingtool.client.raphaelgwt.MyDrawing;
import com.appspot.ldsdrawingtool.client.services.LDSModelUpdaterService;
import com.appspot.ldsdrawingtool.client.services.UserAccountService;
import com.google.gwt.appengine.channel.client.Channel;
import com.google.gwt.appengine.channel.client.ChannelFactory;
import com.google.gwt.appengine.channel.client.ChannelFactory.ChannelCreatedCallback;
import com.google.gwt.appengine.channel.client.SocketError;
import com.google.gwt.appengine.channel.client.SocketListener;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class LdtEntryPoint implements EntryPoint {

    private final Label ldsModelLabel = new Label();
    private final TextBox ldsModelInputBox = new TextBox();
    private final Label userIDBox = new Label();

    /**
     * This is the entry point method.
     */
    public void onModuleLoad() {
        // Try to load in the default LDS model
        loadDefaultModel();

        // Create some anonymous user channel
        createAnonymousUserChannel();
        
        // Set up UI
        setUpUI();

    }

    private void createAnonymousUserChannel() {
        UserAccountService.createAnonymousUserChannel(new AsyncCallback<String>() {
            @Override
            public void onFailure(Throwable caught) {
                caught.printStackTrace();
            }
            @Override
            public void onSuccess(String token) {
                userIDBox.setText("Logged in as " + UserAccountService.userID);
                ChannelFactory.createChannel(token, getChannelCallback());
            }
        });
    }

    private void loadDefaultModel() {
        LDSModelUpdaterService.loadDefaultLDSModel(new AsyncCallback<LDSClientModel>() {
            @Override
            public void onFailure(Throwable caught) {
                caught.printStackTrace();
            }
            @Override
            public void onSuccess(LDSClientModel clientModel) {
                LDSClientModel.setModel(clientModel);
                ldsModelLabel.setText(LDSClientModel.get().getName());
            }
        });
    }
    
    private ChannelCreatedCallback getChannelCallback() {
       return new ChannelCreatedCallback() {
            @Override
            public void onChannelCreated(Channel channel) {
                channel.open(new SocketListener() {
                    @Override
                    public void onOpen() {
                        Window.alert("Channel opened!");
                    }
                    @Override
                    public void onMessage(String message) {
                        ldsModelLabel.setText(message);
                        Window.alert("Model Name was changed!");
                    }
                    @Override
                    public void onError(SocketError error) {
                        Window.alert("Error: " + error.getDescription());
                    }
                    @Override
                    public void onClose() {
                        Window.alert("Channel closed!");
                    }
                });
            }
       };
    }

    // A generic textbox+button handler
    private class TextBoxButtonHandler implements ClickHandler, KeyUpHandler {

        // Fired when the user clicks on the sendButton.
        public void onClick(ClickEvent event) {
            sendPayloadToServer();
        }

        // Fired when the user types in the nameField.
        public void onKeyUp(KeyUpEvent event) {
            if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
                sendPayloadToServer();
            }
        }

        // Send the payload to the server and wait for a response.
        private void sendPayloadToServer() {
            LDSModelUpdaterService.setLDSModelName(LDSClientModel.get().getIdentifer(), ldsModelInputBox.getText(), new AsyncCallback<String>() {
                @Override
                public void onFailure(Throwable caught) {
                    caught.printStackTrace();
                }

                @Override
                public void onSuccess(String result) {
                    // This should be handled by the channel API
                    // ldsModelTextBox.setText(result);
                }
            });
        }
    }
    
    
    
    
    public void setUpUI() {
        
        VerticalPanel mainPanel = new VerticalPanel();
        mainPanel.setWidth("100%");
        
        HorizontalPanel statusPanel = new HorizontalPanel();
        statusPanel.setWidth("100%");
        
        statusPanel.add(ldsModelLabel);
        statusPanel.setCellHorizontalAlignment(ldsModelLabel, HasHorizontalAlignment.ALIGN_LEFT);
        
        HorizontalPanel statusPanelRight = new HorizontalPanel();
        statusPanelRight.add(userIDBox);
        Button loginLogoutButton = new Button("Logout");
        statusPanelRight.add(loginLogoutButton);
        
        statusPanel.add(statusPanelRight);
        statusPanel.setCellHorizontalAlignment(statusPanelRight, HasHorizontalAlignment.ALIGN_RIGHT);
        
        mainPanel.add(statusPanel);
        
        // Make some sub-menus that we will cascade from the top menu.
        MenuBar fileMenu = new MenuBar(true);
        fileMenu.addItem("New", new NewCommand());
        fileMenu.addItem("Open...", new OpenCommand());
        fileMenu.addItem("Save", new SaveCommand());
        fileMenu.addItem("Save As...", new SaveAsCommand());
        fileMenu.addItem("Export...", new ExportCommand());
        fileMenu.addItem("Share...", new ShareCommand());

        MenuBar editMenu = new MenuBar(true);
        editMenu.addItem("Undo", new UndoCommand());
        editMenu.addItem("Redo", new RedoCommand());
        editMenu.addSeparator();
        editMenu.addItem("Cut", new CutCommand());
        editMenu.addItem("Copy", new CopyCommand());
        editMenu.addItem("Paste", new PasteCommand());
        editMenu.addItem("Delete", new DeleteCommand());
        editMenu.addItem("Select All", new SelectAllCommand());

        MenuBar viewMenu = new MenuBar(true);
        viewMenu.addItem("Zoom In", new ZoomInCommand());
        viewMenu.addItem("Zoom Out", new ZoomOutCommand());
        viewMenu.addItem("View All", new ViewAllCommand());
        viewMenu.addSeparator();
        viewMenu.addItem("Show Syntax Errors", new ShowSyntaxErrorsCommand());
        viewMenu.addItem("Show Suggestions", new ShowSuggestionsCommand());
        
        MenuBar insertMenu = new MenuBar(true);
        insertMenu.addItem("Entity", new EntityCommand());
        insertMenu.addItem("Relationship", new RelationshipCommand());
        
        MenuBar toolsMenu = new MenuBar(true);
        toolsMenu.addItem("Generate Natural Language", new GenerateNaturalLanguageCommand());
        
        MenuBar helpMenu = new MenuBar(true);
        helpMenu.addItem("About", new AboutCommand());
        helpMenu.addItem("Get Help Online", new GetHelpOnlineCommand());

        // Make a new menu bar, adding the drop down menus to it
        MenuBar menu = new MenuBar();
        menu.addItem("File", fileMenu);
        menu.addItem("Edit", editMenu);
        menu.addItem("View", viewMenu);
        menu.addItem("Insert", insertMenu);
        menu.addItem("Tools", toolsMenu);
        menu.addItem("Help", helpMenu);

        // Add the menu to the root panel
        mainPanel.add(menu);
        
        
        // Set up the model stuff
        final Button leftModelButton = new Button("Update Model Name");
        ldsModelInputBox.setText("New Name");

        // Add the elements to the root panel
        // Use RootPanel.get() to get the entire body element
        mainPanel.add(ldsModelInputBox);
        mainPanel.add(leftModelButton);

        // Focus the cursor on the left model input box when the app loads
        ldsModelInputBox.setFocus(true);
        ldsModelInputBox.selectAll();

        // Add handlers
        TextBoxButtonHandler ldsModelHandler = new TextBoxButtonHandler();
        leftModelButton.addClickHandler(ldsModelHandler);
        ldsModelInputBox.addKeyUpHandler(ldsModelHandler);
        
        // RaphaelGWT example
        MyDrawing d = new MyDrawing(500, 500);
        mainPanel.add(d);
        
        
        RootPanel.get().add(mainPanel);
    }

}